package org.wx.io.netty.chart.server;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.IdleStateHandler;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.BeforeEach;
import org.wx.io.netty.chart.server.ChartServerHandler;

import java.util.concurrent.TimeUnit;

/**
 * @description: netty 群聊系统
 * @author: wangxun
 * @createDate: 2021/2/18
 * @version: 1.0
 */
@Slf4j
public class NettyChartServer {
    static NioEventLoopGroup bossGroup;
    static NioEventLoopGroup workerGroup;
    static ServerBootstrap serverBootstrap;
    static long startTime;
    static long endTime;

    /**
     * 初始化NioEventLoopGroup
     */
    @BeforeEach
    static void   initServer(){
        startTime = System.currentTimeMillis();
        bossGroup = new NioEventLoopGroup(1);
        workerGroup = new NioEventLoopGroup();
        serverBootstrap = new ServerBootstrap();

        serverBootstrap.group(bossGroup, workerGroup)
                .channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer<SocketChannel>() {

                    @Override
                    protected void initChannel(SocketChannel ch) throws Exception {
                        ChannelPipeline pipeline = ch.pipeline();
                        pipeline.addLast(new LoggingHandler(LogLevel.TRACE));
                        /**
                         * long readerIdleTime 读空闲时间 超过设定时间，就会发送一个心跳检测
                         * long writerIdleTime 写空闲时间
                         * long allIdleTime    读写空闲时间
                         * TimeUnit unit       时间单位
                         * 在IdleStateHandler 会记录最后一次调用的 channelRead 方法的时间
                         * 在初始化的方法内，会新建对应的定时任务去比较时间
                         * 如果超过规定的时间，那么就会调用下一个handler的channelUnregistered方法
                         * 这里没有定时的去与客户端进行tcp包的传递
                         */
                        //pipeline.addLast(new IdleStateHandler(3,5,7, TimeUnit.SECONDS));
                        pipeline.addLast(new ChartServerHandler());
                    }
                });

    }

    public static void main(String[] args) {
        initServer();

        try {
            ChannelFuture future = serverBootstrap.bind(9000).sync();
            /*
               添加监听
             */
            future.addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture future) throws Exception {
                    log.info("服务器已开启，开启的地址是{}",future.channel().localAddress());
                }
            });
            /*
                关闭时发生
             */
            ChannelFuture closeFuture = future.channel().closeFuture().sync();
            closeFuture.addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture future) throws Exception {
                    endTime = System.currentTimeMillis();
                    log.info("服务器已经关闭,一共运行的时间是{}",(endTime-startTime));
                }
            });


        } catch (InterruptedException e) {
            log.error("服务器发生故障，故障原因{}",e.getMessage());

        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }


}
